package msgo

import (
	"fmt"
	"github.com.godemo/msgo/config"
	msLog "github.com.godemo/msgo/log"
	"github.com.godemo/msgo/render"
	"html/template"
	"log"
	"net/http"
	"sync"
)

const ANY = "ANY"

type HandlerFunc func(ctx *Context)

type MiddlewareFunc func(handlerFunc HandlerFunc) HandlerFunc

type routerGroup struct {
	//路由组名称
	groupName string
	// 路由处理器 第一个key表示路由名称，第二个key表示方式
	handlerMap map[string]map[string]HandlerFunc
	//路由级别中间件
	middlewaresFuncMap map[string]map[string][]MiddlewareFunc
	// 请求方式 下允许哪些路由
	handlerMethodMap map[string][]string
	// 路由树
	treeNode *treeNode
	//通用中间件
	preMiddlewares []MiddlewareFunc
}

type route struct {
	group  []*routerGroup
	engine *Engine
}

type Engine struct {
	*route
	funcMap      template.FuncMap
	HTMLRender   render.HTMLRender
	pool         sync.Pool
	Logger       *msLog.Logger
	middles      []MiddlewareFunc
	errorHandler ErrorHandler
}

type ErrorHandler func(err error) (int, any)

func (e *Engine) SetFuncMap(funcMap template.FuncMap) {
	e.funcMap = funcMap
}

func (e *Engine) LoadTemplate(patter string) {
	t := template.Must(template.New("").Funcs(e.funcMap).ParseGlob(patter))
	e.SetHtmlTemplate(t)
}

func (e *Engine) LoadTemplateGlobByConf() {
	pattern, ok := config.Conf.Template["pattern"]
	if !ok {
		panic("config pattern not exist")
	}
	t := template.Must(template.New("").Funcs(e.funcMap).ParseGlob(pattern.(string)))
	e.SetHtmlTemplate(t)
}

func (e *Engine) SetHtmlTemplate(t *template.Template) {
	e.HTMLRender = render.HTMLRender{Template: t}
}

/**
 * 添加路由
 */

func (r *routerGroup) handle(name, method string, handlerFunc HandlerFunc, middlewares ...MiddlewareFunc) {
	if _, ok := r.handlerMap[name]; !ok {
		r.handlerMap[name] = make(map[string]HandlerFunc)
		r.middlewaresFuncMap[name] = make(map[string][]MiddlewareFunc)
	}
	if _, ok := r.handlerMap[name][method]; ok {
		panic("handler already exists")
	}
	r.handlerMap[name][method] = handlerFunc
	r.handlerMethodMap[method] = append(r.handlerMethodMap[method], name)
	r.middlewaresFuncMap[name][method] = append(r.middlewaresFuncMap[name][method], middlewares...)
	r.treeNode.Put(name)
}
func (r *routerGroup) Get(name string, handlerFunc HandlerFunc, middlewares ...MiddlewareFunc) {
	r.handle(name, http.MethodGet, handlerFunc, middlewares...)
}

func (r *routerGroup) Post(name string, handlerFunc HandlerFunc, middlewares ...MiddlewareFunc) {
	r.handle(name, http.MethodPost, handlerFunc, middlewares...)
}

func (r *routerGroup) Delete(name string, handlerFunc HandlerFunc, middlewares ...MiddlewareFunc) {
	r.handle(name, http.MethodDelete, handlerFunc, middlewares...)
}

func (r *routerGroup) Put(name string, handlerFunc HandlerFunc, middlewares ...MiddlewareFunc) {
	r.handle(name, http.MethodPut, handlerFunc, middlewares...)
}

func (r *routerGroup) Any(name string, handlerFunc HandlerFunc, middlewares ...MiddlewareFunc) {
	r.handle(name, ANY, handlerFunc, middlewares...)
}

func (r *routerGroup) Patch(name string, handlerFunc HandlerFunc, middlewares ...MiddlewareFunc) {
	r.handle(name, http.MethodPatch, handlerFunc, middlewares...)
}
func (r *routerGroup) Options(name string, handlerFunc HandlerFunc, middlewares ...MiddlewareFunc) {
	r.handle(name, http.MethodOptions, handlerFunc, middlewares...)
}
func (r *routerGroup) Head(name string, handlerFunc HandlerFunc, middlewares ...MiddlewareFunc) {
	r.handle(name, http.MethodHead, handlerFunc, middlewares...)
}

/**
 * 创建一个路由组
 */
func (r *route) Group(name string) *routerGroup {
	g := &routerGroup{
		groupName:          name,
		handlerMap:         make(map[string]map[string]HandlerFunc),
		middlewaresFuncMap: make(map[string]map[string][]MiddlewareFunc),
		handlerMethodMap:   make(map[string][]string),
		treeNode:           &treeNode{name: "/", children: make([]*treeNode, 0)},
	}
	g.PreHandle(r.engine.middles...)
	r.group = append(r.group, g)
	return g
}

func New() *Engine {
	engine := &Engine{
		route: &route{}, funcMap: nil, HTMLRender: render.HTMLRender{Template: nil},
	}
	engine.pool.New = func() any {
		return engine.aollocateContext()
	}
	return engine

}

func Default() *Engine {
	engine := New()
	engine.Logger = msLog.Default()
	if logPath, ok := config.Conf.Log["path"]; ok {
		engine.Logger.SetLogPath(logPath.(string))
	}
	engine.Use(Logging, Recovery)
	engine.route.engine = engine
	return engine
}
func (e *Engine) aollocateContext() any {
	return &Context{
		engine: e,
	}
}

func (r *routerGroup) PreHandle(middlewares ...MiddlewareFunc) {
	r.preMiddlewares = append(r.preMiddlewares, middlewares...)
}

/**
 * h 处理请求的业务函数
 */
func (r *routerGroup) methodHandle(name, method string, h HandlerFunc, ctx *Context) {
	//组内通用中间件处理
	if r.preMiddlewares != nil {
		for _, middleware := range r.preMiddlewares {
			h = middleware(h)
		}
	}
	//组内路由级别中间件处理
	middlewares := r.middlewaresFuncMap[name][method]
	if middlewares != nil {
		for _, middleware := range middlewares {
			h = middleware(h)
		}
	}
	h(ctx)
}
func (e *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	ctx := e.pool.Get().(*Context)
	ctx.R = r
	ctx.W = w
	ctx.Logger = e.Logger
	e.httpRequestHandle(ctx, w, r)
	e.pool.Put(ctx)
}

func (e *Engine) httpRequestHandle(ctx *Context, w http.ResponseWriter, r *http.Request) {
	method := r.Method
	for _, groups := range e.group {
		routerName := SubStringLast(r.URL.Path, "/"+groups.groupName)
		// get/1
		node := groups.treeNode.Get(routerName)
		if node != nil && node.isEnd {
			//路由匹配上了
			handle, ok := groups.handlerMap[routerName][ANY]
			if ok {
				groups.methodHandle(routerName, ANY, handle, ctx)
				return
			}
			handle, ok = groups.handlerMap[routerName][method]
			if ok {
				groups.methodHandle(routerName, method, handle, ctx)
				return
			}
			w.WriteHeader(http.StatusMethodNotAllowed)
			fmt.Fprintf(w, "%s %s not allowed \n", r.URL.Path, method)
			return
		}
	}
	w.WriteHeader(http.StatusNotFound)
	fmt.Fprintf(w, "%s  not found \n", r.URL.Path)
}

func (e *Engine) Run() {
	http.Handle("/", e)
	err := http.ListenAndServe(":8080", nil)
	if err != nil {
		log.Fatal(err)
	}
}

func (e *Engine) RunTLS(addr, certFile, keyFile string) {
	err := http.ListenAndServeTLS(addr, certFile, keyFile, e.Handler())
	if err != nil {
		log.Fatal(err)
	}
}

func (e *Engine) Use(middles ...MiddlewareFunc) {
	e.middles = append(e.middles, middles...)
}

func (e *Engine) RegisterErrorHandler(err ErrorHandler) {
	e.errorHandler = err
}

func (e *Engine) Handler() http.Handler {
	return e
}
